package org.wang.generalcode.modules.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.wang.generalcode.modules.sys.pojo.entity.Dept;
import org.wang.generalcode.modules.sys.pojo.enums.StatusEnum;
import org.wang.generalcode.modules.sys.pojo.model.Option;
import org.wang.generalcode.modules.sys.pojo.params.DeptQueryParams;
import org.wang.generalcode.modules.sys.pojo.vo.DeptVO;
import org.wang.generalcode.modules.sys.mapper.DeptMapper;
import org.wang.generalcode.modules.sys.service.IDeptService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 部门表 服务实现类
 *
 * @author wz
 * @since 2024-08-08
 */
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {

	@Override
	public IPage<DeptVO> selectDeptPage(IPage<DeptVO> page, DeptVO dept) {
		return page.setRecords(baseMapper.selectDeptPage(page, dept));
	}

	@Override
	public List<DeptVO> getDeptList(DeptQueryParams queryParams) {
		// 查询参数
		String keywords = queryParams.getKeywords();
		Integer status = queryParams.getStatus();

		// 查询数据
		List<Dept> deptList = this.list(
				new LambdaQueryWrapper<Dept>()
						.like(StrUtil.isNotBlank(keywords), Dept::getName, keywords)
						.eq(status != null, Dept::getStatus, status)
						.orderByAsc(Dept::getSort)
		);

		if (CollectionUtil.isEmpty(deptList)) {
			return Collections.EMPTY_LIST;
		}

		// 获取所有部门ID
		Set<Long> deptIds = deptList.stream()
				.map(Dept::getId)
				.collect(Collectors.toSet());
		// 获取父节点ID
		Set<Long> parentIds = deptList.stream()
				.map(Dept::getParentId)
				.collect(Collectors.toSet());
		// 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级部门 O 作为根节点，因为部门筛选的时候 O 会被过滤掉
		List<Long> rootIds = CollectionUtil.subtractToList(parentIds, deptIds);

		// 递归生成部门树形列表
		return rootIds.stream()
				.flatMap(rootId -> recurDeptList(rootId, deptList).stream())
				.toList();
	}

	@Override
	public List<Option<Long>> listDeptOptions() {

		List<Dept> deptList = this.list(new LambdaQueryWrapper<Dept>()
				.eq(Dept::getStatus, StatusEnum.ENABLE.getValue())
				.select(Dept::getId, Dept::getParentId, Dept::getName)
				.orderByAsc(Dept::getSort)
		);
		if (CollectionUtil.isEmpty(deptList)) {
			return Collections.EMPTY_LIST;
		}

		Set<Long> deptIds = deptList.stream()
				.map(Dept::getId)
				.collect(Collectors.toSet());

		Set<Long> parentIds = deptList.stream()
				.map(Dept::getParentId)
				.collect(Collectors.toSet());

		List<Long> rootIds = CollectionUtil.subtractToList(parentIds, deptIds);

		// 递归生成部门树形列表
		return rootIds.stream()
				.flatMap(rootId -> recurDeptTreeOptions(rootId, deptList).stream())
				.toList();
	}

	/**
	 * 递归生成部门树形列表
	 *
	 * @param parentId 父ID
	 * @param deptList 部门列表
	 * @return 部门树形列表
	 */
	public List<DeptVO> recurDeptList(Long parentId, List<Dept> deptList) {
		return deptList.stream()
				.filter(dept -> dept.getParentId().equals(parentId))
				.map(dept -> {
					DeptVO deptVO = BeanUtil.copyProperties(dept, DeptVO.class);
					List<DeptVO> children = recurDeptList(dept.getId(), deptList);
					deptVO.setChildren(children);
					return deptVO;
				}).toList();
	}

	/**
	 * 递归生成部门表格层级列表
	 *
	 * @param parentId 父ID
	 * @param deptList 部门列表
	 * @return 部门表格层级列表
	 */
	public static List<Option<Long>> recurDeptTreeOptions(long parentId, List<Dept> deptList) {
		return CollectionUtil.emptyIfNull(deptList).stream()
				.filter(dept -> dept.getParentId().equals(parentId))
				.map(dept -> {
					Option<Long> option = new Option<>(dept.getId(), dept.getName());
					List<Option<Long>> children = recurDeptTreeOptions(dept.getId(), deptList);
					if (CollectionUtil.isNotEmpty(children)) {
						option.setChildren(children);
					}
					return option;
				})
				.collect(Collectors.toList());
	}

}
